from typing import Any, List, Dict, Optional, Union
import copy
from .msg import Msg

class Messenger:
    """
    消息容器类。

    该类支持从字符串、字典列表、或另一个 ``Messenger`` 对象初始化。

    Examples:
        >>> m = Messenger("你好")
        >>> m.add("img", "https://example.com/a.png")
        >>> print(m)
        [{'text': '你好'}, {'img': 'https://example.com/a.png'}]
    """

    def __init__(self, data: Optional[Union[str, 'Messenger', List[Dict[str, str]]]] = None):
        """
        构造函数。

        根据传入的 ``data`` 类型，将消息内容解析并填充到内部列表 ``self.list`` 中。

        Args:
            data: 可选的初始化数据。
                - ``None``：创建一个空容器。
                - ``str``：自动作为纯文本消息添加。
                - ``Messenger``：深拷贝其内部消息列表。
                - ``List[Dict[str, str]]``：直接追加到内部列表。
        """
        self.list: List[Dict[str, str]] = []

        if data is None:
            pass
        elif isinstance(data, str):
            self.addMsg(data)
        elif isinstance(data, Messenger):
            if data.list is not None:
                self.list.extend(copy.deepcopy(data.list))
        elif isinstance(data, list):
            if data is not None:
                self.list.extend(data)

    @staticmethod
    def newObject(data: Optional[List[Dict[str, str]]] = None) -> 'Messenger':
        """
        静态工厂方法，快速创建一个新的 ``Messenger`` 实例。

        Args:
            data: 可选的初始数据，格式为 ``List[Dict[str, str]]``。

        Returns:
            一个新的 ``Messenger`` 对象。
        """
        return Messenger(data)

    def cloneObject(self) -> 'Messenger':
        """
        克隆当前对象，返回一个深拷贝的新实例。

        Returns:
            与当前对象内容完全一致的新 ``Messenger`` 实例。
        """
        return Messenger.newObject(self.getList())

    def get(self, tag: Union[str, int], default: Any = "0") -> Any:
        """
        根据标签或下标获取对应的消息内容。

        Args:
            tag:
                - 若为 ``int``，表示按索引获取单条消息。
                - 若为 ``str``，表示按标签聚合多条消息内容后拼接返回。
            default: 当找不到对应消息时的默认值，默认为 ``"0"``。

        Returns:
            获取到的消息内容，或 ``default``。
        """
        if isinstance(tag, int):
            return self._get_by_index(tag, str(default), default)
        else:
            return self._get_by_tag(tag, default)

    def _get_by_tag(self, tag: str, default: Any = "0") -> Any:
        """
        内部方法：按标签聚合所有匹配消息的内容并拼接。

        Args:
            tag: 消息标签。
            default: 默认值。

        Returns:
            所有匹配消息拼接后的字符串，若为空则返回 ``default``。
        """
        data = ""

        msg_list = self.getList(tag)
        for msg in msg_list:
            data += msg

        return data if len(data) > 0 else default

    def _get_by_index(self, index: int, tag: str, default: Any = "0") -> Any:
        """
        内部方法：按索引获取单条消息中指定标签的值。

        Args:
            index: 消息索引。
            tag: 消息标签。
            default: 默认值。

        Returns:
            对应标签的值，若索引越界或标签不存在则返回 ``default``。
        """
        if len(self.list) > index:
            if tag in self.list[index]:
                return self.list[index][tag]
            else:
                return default
        else:
            return default

    def getList(self, tag: Optional[str] = None) -> Union[List[Dict[str, str]], List[str]]:
        """
        获取消息列表。

        Args:
            tag:
                - ``None``：返回原始 ``List[Dict[str, str]]``。
                - 其他 ``str``：返回所有匹配该标签的值组成的 ``List[str]``。

        Returns:
            消息列表或指定标签的值列表。
        """
        if tag is None:
            return self.list
        else:
            result_list = []

            for map_dict in self.list:
                if tag in map_dict:
                    result_list.append(map_dict[tag])

            return result_list

    def getListSize(self) -> int:
        """
        获取消息条数。

        Returns:
            当前容器中的消息条数。
        """
        return len(self.list)

    def getMsgSize(self, tag: Optional[str] = None) -> int:
        """
        获取消息数量。

        Args:
            tag:
                - ``None``：返回所有标签的总数量（条数 * 每条消息的键值对数）。
                - 其他 ``str``：返回指定标签出现的次数。

        Returns:
            消息数量。
        """
        if tag is None:
            size = 0
            for map_dict in self.list:
                size += len(map_dict)
            return len(self.list) * size
        else:
            count = 0
            for map_dict in self.list:
                if tag in map_dict:
                    count += 1
            return count

    def getChatId(self) -> str:
        """
        根据消息类型自动提取会话 ID。

        目前支持群聊、好友、临时会话、频道四种场景，优先级依次判断。

        Returns:
            对应的会话 ID 字符串；若无法识别类型则返回 ``None``。
        """
        chatId = None
        match Messenger.getMsgType(self):
            case Msg.Group:
                chatId = self.get(Msg.GroupId)
            case Msg.Friend | Msg.Temp:
                chatId = self.get(Msg.Uin)
            case Msg.Guild:
                chatId = self.get(Msg.GuildId)
        return chatId

    def has(self, tag: str) -> bool:
        """
        判断是否存在指定标签的消息。

        Args:
            tag: 消息标签。

        Returns:
            若存在返回 ``True``，否则返回 ``False``。
        """
        for map_dict in self.list:
            if tag in map_dict:
                return True
        return False

    def insert(self, index: int, tag: str, value: str) -> 'Messenger':
        """
        在指定索引位置插入或更新消息。

        Args:
            index: 目标索引，必须在有效范围内。
            tag: 消息标签。
            value: 消息内容。

        Returns:
            当前实例自身，方便链式调用。
        """
        if 0 <= index < len(self.list):
            self.list[index][tag] = value
        return self

    def add(self,
            tag: Union[str, 'Messenger', List[Dict[str, str]], Dict[str, str]],
            value: Optional[Union[str, Any]] = None) -> 'Messenger':
        """
        向容器中追加消息，支持多种重载形式。

        支持的调用方式：
            - ``add("text", "hello")``
            - ``add({"text": "hello", "img": "url"})``
            - ``add([{"text": "a"}, {"img": "b"}])``
            - ``add(another_messenger)``

        Args:
            tag: 消息标签或复合数据。
            value: 当 ``tag`` 为字符串时的消息内容。

        Returns:
            当前实例自身，方便链式调用。
        """
        if tag is None:
            return self

        if isinstance(tag, Messenger):
            if tag is not None:
                self.add(tag.list)
            return self
        elif isinstance(tag, list):
            self.list.extend(tag)
            return self
        elif isinstance(tag, dict):
            if tag is not None:
                for key, val in tag.items():
                    self.add(key, val)
            return self
        elif value is None:
            return self.add(tag, tag)

        tag = str(tag)
        value = str(value) if value is not None else ""

        if not tag or not value:
            return self

        if tag == Msg.AtUin or tag == Msg.AtName or tag == Msg.AtAll:
            if tag == Msg.AtAll:
                pass
            else:
                for map_dict in self.list:
                    if len(map_dict) == 1 and (Msg.AtUin in map_dict or Msg.AtName in map_dict):
                        if tag not in map_dict:
                            map_dict[tag] = value
                            return self
        else:
            if tag == Msg.Text or tag == Msg.Img or tag == Msg.Gif or tag == Msg.Emoid:
                pass
            else:
                for map_dict in self.list:
                    if tag not in map_dict:
                        map_dict[tag] = value
                        return self

        map_dict = {tag: value}
        self.list.append(map_dict)
        return self

    def addArgs(self, tag: str, *values) -> 'Messenger':
        """
        将多个值拼接后作为单条消息追加。

        Args:
            tag: 消息标签。
            *values: 任意数量的待拼接参数，将自动转换为字符串后追加。

        Returns:
            当前实例自身，方便链式调用。
        """
        append = ""
        for s in values:
            append += str(s)
        return self.addMsg(tag, append)

    def delMsg(self, tag: Optional[str] = None) -> 'Messenger':
        """
        删除消息。

        Args:
            tag:
                - ``None``：清空所有消息。
                - 其他 ``str``：仅删除所有匹配该标签的键值对。

        Returns:
            当前实例自身，方便链式调用。
        """
        if tag is None:
            self.list.clear()
        else:
            for map_dict in self.list:
                if tag in map_dict:
                    del map_dict[tag]
        return self

    @staticmethod
    def getBaseMessenger(messenger: 'Messenger') -> 'Messenger':
        """
        根据消息类型快速构造一个仅包含会话基础信息的新对象。

        可用于构造回复消息时预填 ``Account``、``GroupId``、``Uin`` 等字段。

        Args:
            messenger: 原始消息对象。

        Returns:
            包含会话基础信息的新 ``Messenger`` 实例。

        Raises:
            TypeError: 若消息类型暂不支持处理。
        """
        reply = Messenger()
        reply.add(Msg.Account, messenger.get(Msg.Account))
        if messenger.has(Msg.Group):
            reply.add(Msg.Group) \
                 .add(Msg.GroupId, messenger.get(Msg.GroupId))
        elif messenger.has(Msg.Friend):
            reply.add(Msg.Friend) \
                 .add(Msg.Uin, messenger.get(Msg.Uin))
        elif messenger.has(Msg.Temp):
            reply.add(Msg.Temp) \
                 .add(Msg.GroupId, messenger.get(Msg.GroupId)) \
                 .add(Msg.Uin, messenger.get(Msg.Uin))
        elif messenger.has(Msg.Guild):
            reply.add(Msg.Guild) \
                 .add(Msg.GuildId, messenger.get(Msg.GuildId)) \
                 .add(Msg.ChannelId, messenger.get(Msg.ChannelId))
        else:
            raise TypeError("该消息类型暂不支持处理")
        return reply

    @staticmethod
    def getMsgType(messenger: 'Messenger') -> str:
        """
        判断消息类型。

        依次检测是否包含 ``Group``、``Friend``、``Temp``、``Guild`` 标签。

        Args:
            messenger: 待判断的消息对象。

        Returns:
            对应的消息类型字符串；若无法识别则返回 ``None``。
        """
        type = None
        if messenger and isinstance(messenger, Messenger) and messenger.getList():
            if messenger.has(Msg.Group):
                type = Msg.Group
            elif messenger.has(Msg.Friend):
                type = Msg.Friend
            elif messenger.has(Msg.Temp):
                type = Msg.Temp
            elif messenger.has(Msg.Guild):
                type = Msg.Guild
        return type

    def __str__(self) -> str:
        """
        返回便于阅读的字符串表示

        Returns:
            消息列表的字符串形式。
        """
        return json.dumps(self.list, )

    def __repr__(self) -> str:
        """
        返回官方字符串表示，等价于 ``str(self.list)``。

        Returns:
            可用于调试的消息列表字符串。
        """
        return str(self.list)
